Python μ ν리μΌμ΄μ μμ PostgreSQLμ κ°λ ₯ν κΈ°λ₯μ νμ©νμΈμ. μ΄ μ¬μΈ΅ κ°μ΄λλ psycopg2λ₯Ό μ¬μ©ν κΈ°λ³Έ μ°κ²° λ° CRUD μμ λΆν° νΈλμμ κ΄λ¦¬, μ°κ²° νλ§, μ±λ₯ μ΅μ νμ κ°μ κ³ κΈ μ£Όμ κΉμ§ μ μΈκ³ κ°λ°μλ₯Ό λμμΌλ‘ λ€λ£Ήλλ€.
Python PostgreSQL ν΅ν©: Psycopg2 μ’ ν© κ°μ΄λ
μννΈμ¨μ΄ κ°λ° λΆμΌμμ νλ‘κ·Έλλ° μΈμ΄μ λ°μ΄ν°λ² μ΄μ€ κ°μ μλμ§λ κ²¬κ³ νκ³ νμ₯ κ°λ₯νλ©° λ°μ΄ν° μ€μ¬μ μΈ μ ν리μΌμ΄μ μ ꡬμΆνλ λ° νμμ μ λλ€. λ¨μμ±κ³Ό κ°λ ₯ν¨μΌλ‘ μ μλ €μ§ Pythonκ³Ό μ λ’°μ± λ° κ³ κΈ κΈ°λ₯μΌλ‘ λͺ μ±μ΄ λμ PostgreSQLμ μ‘°ν©μ λͺ¨λ κ·λͺ¨μ νλ‘μ νΈλ₯Ό μν κ°λ ₯ν μ€νμ λ§λλλ€. μ΄ λ κΈ°μ μ μ°κ²°νλ λ€λ¦¬λ λ°μ΄ν°λ² μ΄μ€ μ΄λν°μ΄λ©°, PostgreSQLμ κ²½μ° Python μνκ³μ μ¬μ€μμ νμ€μ psycopg2μ λλ€.
μ΄ μ’ ν© κ°μ΄λλ λ°μ΄ν°λ² μ΄μ€ ν΅ν©μ μ²μ μμνλ κ°λ°μλΆν° κΈ°μ μ λ€λ¬μΌλ €λ μλ ¨λ μμ§λμ΄κΉμ§ μ μΈκ³ κ°λ°μλ₯Ό λμμΌλ‘ ν©λλ€. 첫 λ²μ§Έ μ°κ²°λΆν° κ³ κΈ μ±λ₯ μ΅μ ν κΈ°μ μ μ΄λ₯΄κΈ°κΉμ§ psycopg2 λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μΈ΅μ μΌλ‘ νꡬν κ²μ λλ€. μ ν¬λ μ ν리μΌμ΄μ μ΄ μμ νκ³ ν¨μ¨μ μ΄λ©° μ μ§λ³΄μ κ°λ₯νλλ‘ λ³΄μ₯νλ λͺ¨λ² μ¬λ‘μ μ€μ μ λ κ²μ λλ€.
Pythonκ³Ό PostgreSQLμ μ ν¨κ» μ¬μ©λ κΉμ? κ°λ ₯ν λλ§Ή
psycopg2μ κΈ°μ μ μΈ μΈλΆ μ¬νμ λ€μ΄κ°κΈ° μ μ, μ΄ μ‘°ν©μ΄ μ κ·Έλ κ² λμ΄ νκ°λλμ§ μ΄ν΄ν κ°μΉκ° μμ΅λλ€:
- Pythonμ κ°μ : κΉλν ꡬ문, κ΄λ²μν νμ€ λΌμ΄λΈλ¬λ¦¬, κ·Έλ¦¬κ³ λ°©λν μλνν° ν¨ν€μ§ μνκ³λ μΉ κ°λ°, λ°μ΄ν° λΆμ, μΈκ³΅ μ§λ₯ λ±μ μ΄μμ μ λλ€. κ°λ°μ μμ°μ±κ³Ό μ½λ κ°λ μ±μ μ°μ μν©λλ€.
- PostgreSQLμ κ°μ : μ’ μ’ "μΈκ³μμ κ°μ₯ μ§λ³΄λ μ€ν μμ€ κ΄κ³ν λ°μ΄ν°λ² μ΄μ€"λΌκ³ λΆλ¦¬λ PostgreSQLμ ACIDλ₯Ό μ€μνλ©°, κ³ λλ‘ νμ₯ κ°λ₯νκ³ , JSON, XML, μ§λ¦¬ κ³΅κ° λ°μ΄ν° λ± λ°©λν λ°μ΄ν° μ νμ μ§μν©λλ€. λ°μ΄ν° 무결μ±κ³Ό μ±λ₯μΌλ‘ μ€ννΈμ κ³Ό λκΈ°μ λͺ¨λμκ² μ λ’°λ°κ³ μμ΅λλ€.
- Psycopg2: μλ²½ν λ²μκΈ°: Psycopg2λ μ±μνκ³ , νλ°νκ² μ μ§λ³΄μλλ©°, κΈ°λ₯μ΄ νλΆν μ΄λν°μ λλ€. Python λ°μ΄ν° μ νμ PostgreSQL μ νμΌλ‘, κ·Έλ¦¬κ³ κ·Έ λ°λλ‘ ν¨μ¨μ μΌλ‘ λ³ννμ¬ λ°μ΄ν°λ² μ΄μ€ ν΅μ μ μν μννκ³ μ±λ₯ μ’μ μΈν°νμ΄μ€λ₯Ό μ 곡ν©λλ€.
κ°λ° νκ²½ μ€μ
μ΄ κ°μ΄λλ₯Ό λ°λΌ νλ €λ©΄ λͺ κ°μ§ μ μ μ‘°κ±΄μ΄ νμν©λλ€. Pythonκ³Ό PostgreSQL μλ²κ° μ΄λ―Έ μ€ν μ€μ΄λΌκ³ κ°μ νκ³ λΌμ΄λΈλ¬λ¦¬ μ체 μ€μΉμ μ€μ μ λ κ²μ λλ€.
μ¬μ μ€λΉ μ¬ν
- Python: μμ€ν μ μ€μΉλ μ΅μ λ²μ μ Python (3.7 μ΄μ κΆμ₯).
- PostgreSQL: PostgreSQL μλ²μ λν μ κ·Ό. μ΄λ λ‘컬 λ¨Έμ μ μ€μΉλκ±°λ, 컨ν μ΄λνλ μΈμ€ν΄μ€(μ: Docker μ¬μ©), λλ ν΄λΌμ°λ νΈμ€ν λ°μ΄ν°λ² μ΄μ€ μλΉμ€μΌ μ μμ΅λλ€. μ격 μ¦λͺ (λ°μ΄ν°λ² μ΄μ€ μ΄λ¦, μ¬μ©μ, λΉλ°λ²νΈ) λ° μ°κ²° μΈλΆ μ 보(νΈμ€νΈ, ν¬νΈ)κ° νμν©λλ€.
- Python κ°μ νκ²½ (κ°λ ₯ κΆμ₯): μμ€ν μ 체 ν¨ν€μ§μμ μΆ©λμ νΌνκΈ° μν΄ κ°μ νκ²½ λ΄μμ μμ νλ κ²μ΄ κ°μ₯ μ’μ΅λλ€. `python3 -m venv myproject_env`λ₯Ό μ¬μ©νμ¬ κ°μ νκ²½μ μμ±νκ³ νμ±νν μ μμ΅λλ€.
Psycopg2 μ€μΉ
psycopg2λ₯Ό μ€μΉνλ κΆμ₯ λ°©λ²μ λ°μ΄λ리 ν¨ν€μ§λ₯Ό μ¬μ©νλ κ²μ λλ€. μ΄λ μμ€μμ μ»΄νμΌνκ³ C μμ€ μ’ μμ±μ κ΄λ¦¬νλ λ²κ±°λ‘μμ λμ΄μ€λλ€. ν°λ―Έλ λλ λͺ λ Ή ν둬ννΈ(κ°μ νκ²½μ΄ νμ±νλ μνμμ)λ₯Ό μ΄κ³ λ€μμ μ€ννμΈμ:
pip install psycopg2-binary
λλλ‘ `pip install psycopg2`μ λν μ°Έμ‘°λ₯Ό λ³Ό μ μμ΅λλ€. `psycopg2` ν¨ν€μ§λ μμ€ν μ λΉλ λꡬμ PostgreSQL κ°λ° ν€λκ° μ€μΉλμ΄ μμ΄μΌ νλ©°, μ΄λ 볡μ‘ν μ μμ΅λλ€. `psycopg2-binary` ν¨ν€μ§λ λλΆλΆμ νμ€ μ΄μ 체μ μμ μ¦μ μλνλ μ¬μ μ»΄νμΌλ λ²μ μ΄λ―λ‘, μ ν리μΌμ΄μ κ°λ°μ μ νΈλλ μ νμ λλ€.
λ°μ΄ν°λ² μ΄μ€ μ°κ²° μ€μ
λͺ¨λ λ°μ΄ν°λ² μ΄μ€ μνΈ μμ©μ 첫 λ²μ§Έ λ¨κ³λ μ°κ²°μ μ€μ νλ κ²μ λλ€. Psycopg2λ `psycopg2.connect()` ν¨μλ₯Ό μ¬μ©νμ¬ μ΄λ₯Ό κ°λ¨νκ² λ§λλλ€.
μ°κ²° λ§€κ°λ³μ
The `connect()` function can accept connection parameters in a few ways, but the most common and readable method is using keyword arguments or a single connection string (DSN - Data Source Name).
μ£Όμ λ§€κ°λ³μλ λ€μκ³Ό κ°μ΅λλ€:
dbname: μ°κ²°νλ €λ λ°μ΄ν°λ² μ΄μ€μ μ΄λ¦.user: μΈμ¦μ μν μ¬μ©μ μ΄λ¦.password: μ§μ λ μ¬μ©μμ λΉλ°λ²νΈ.host: λ°μ΄ν°λ² μ΄μ€ μλ² μ£Όμ (μ: 'localhost' λλ IP μ£Όμ).port: μλ²κ° μμ λκΈ°νλ ν¬νΈ λ²νΈ (PostgreSQLμ κΈ°λ³Έκ°μ 5432).
보μμ λν νλ§λ: μ격 μ¦λͺ μ νλμ½λ©νμ§ λ§μΈμ!
μ€μν 보μ λͺ¨λ² μ¬λ‘λ λ°μ΄ν°λ² μ΄μ€ μ격 μ¦λͺ μ μμ€ μ½λμ μ§μ νλμ½λ©νμ§ μλ κ²μ λλ€. μ΄λ λ―Όκ°ν μ 보λ₯Ό λ ΈμΆμν€κ³ λ€λ₯Έ νκ²½(κ°λ°, μ€ν μ΄μ§, νλ‘λμ )μ κ΄λ¦¬νκΈ° μ΄λ ΅κ² λ§λλλ€. λμ νκ²½ λ³μ λλ μ μ© κ΅¬μ± κ΄λ¦¬ μμ€ν μ μ¬μ©νμΈμ.
컨ν μ€νΈ κ΄λ¦¬μλ‘ μ°κ²°νκΈ°
μ°κ²°μ κ΄λ¦¬νλ κ°μ₯ Pythonμ€λ¬μ΄(Pythonic) μμ ν λ°©λ²μ `with` λ¬Έμ μ¬μ©νλ κ²μ λλ€. μ΄λ λΈλ‘ λ΄μμ μ€λ₯κ° λ°μνλλΌλ μ°κ²°μ΄ μλμΌλ‘ λ«νλλ‘ λ³΄μ₯ν©λλ€.
import psycopg2
import os # Used to get environment variables
try:
# It's a best practice to load credentials from environment variables
# or a secure configuration file, not hardcode them.
with psycopg2.connect(
dbname=os.environ.get("DB_NAME"),
user=os.environ.get("DB_USER"),
password=os.environ.get("DB_PASSWORD"),
host=os.environ.get("DB_HOST", "127.0.0.1"),
port=os.environ.get("DB_PORT", "5432")
) as conn:
print("Connection to PostgreSQL successful!")
# You can perform database operations here
except psycopg2.OperationalError as e:
print(f"Could not connect to the database: {e}")
컀μ: λͺ λ Ή μ€νμ κ΄λ¬Έ
μ°κ²°μ΄ μ€μ λλ©΄ κ·Έ μμ μ§μ 쿼리λ₯Ό μ€νν μ μμ΅λλ€. 컀μλΌκ³ λΆλ¦¬λ μ€κ° κ°μ²΄κ° νμν©λλ€. 컀μλ λ°μ΄ν°λ² μ΄μ€ μΈμ μ μΊ‘μννμ¬ μνλ₯Ό μ μ§νλ©΄μ ν΄λΉ μΈμ λ΄μμ μ¬λ¬ λͺ λ Ήμ μ€νν μ μλλ‘ ν©λλ€.
μ°κ²°μ λ°μ΄ν°λ² μ΄μ€λ‘ κ°λ μ νμ μΌλ‘ μκ°νκ³ , 컀μλ κ·Έ μ νμ μΌλ‘ λλλ λνλΌκ³ μκ°νμΈμ. νμ± μ°κ²°μμ 컀μλ₯Ό μμ±ν©λλ€.
μ°κ²°κ³Ό λ§μ°¬κ°μ§λ‘ 컀μλ `with` λ¬ΈμΌλ‘ κ΄λ¦¬νμ¬ μ¬λ°λ₯΄κ² λ«νκ³ λ³΄μ ν 리μμ€κ° ν΄μ λλλ‘ ν΄μΌ ν©λλ€.
# ... inside the 'with psycopg2.connect(...) as conn:' block
with conn.cursor() as cur:
# Now you can execute queries using 'cur'
cur.execute("SELECT version();")
db_version = cur.fetchone()
print(f"Database version: {db_version}")
쿼리 μ€ν: ν΅μ¬ CRUD μμ
CRUDλ Create(μμ±), Read(μ½κΈ°), Update(μ λ°μ΄νΈ), Delete(μμ )λ₯Ό μλ―Έν©λλ€. μ΄λ λͺ¨λ μꡬ μ μ₯ μμ€ν μ λ€ κ°μ§ κΈ°λ³Έ μμ μ λλ€. psycopg2λ‘ κ° μμ μ μννλ λ°©λ²μ μ΄ν΄λ³΄κ² μ΅λλ€.
μ€μν 보μ μ°Έκ³ μ¬ν: SQL Injection
μ¬μ©μ μ λ ₯μ ν¬ν¨νλ 쿼리λ₯Ό μμ±νκΈ° μ μ κ°μ₯ μ€μν 보μ μνμΈ SQL Injectionμ λ€λ£¨μ΄μΌ ν©λλ€. μ΄ κ³΅κ²©μ 곡격μκ° μ μ± SQL μ½λλ₯Ό λ°μ΄ν° μ λ ₯μ μ½μ νμ¬ SQL 쿼리λ₯Ό μ‘°μν μ μμ λ λ°μν©λλ€.
μΈλΆ λ°μ΄ν°λ₯Ό μ¬μ©νμ¬ μΏΌλ¦¬λ₯Ό μμ±ν λ Pythonμ λ¬Έμμ΄ νμ μ§μ (f-strings, `%` μ°μ°μ λλ `.format()`)μ μ λ μ¬μ©νμ§ λ§μΈμ. μ΄λ λ§€μ° μνν©λλ€.
μλͺ»λκ³ μνν¨:
cur.execute(f"SELECT * FROM users WHERE username = '{user_input}';")
μ¬λ°λ₯΄κ³ μμ ν¨:
Psycopg2λ 쿼리μ λ§€κ°λ³μλ₯Ό μμ νκ² μ λ¬νλ λ°©λ²μ μ 곡ν©λλ€. SQL λ¬Έμμ΄μ νλ μ΄μ€νλ(%s)λ₯Ό μ¬μ©νκ³ , `execute()`μ λ λ²μ§Έ μΈμλ‘ κ° ννμ μ λ¬ν©λλ€. μ΄λν°λ κ°μ μ μ ν μ΄μ€μΌμ΄ν λ° λ°μ΄ν μ²λ¦¬λ₯Ό λ΄λΉνμ¬ μ
μ± μ
λ ₯μ 무λ ₯νν©λλ€.
cur.execute("SELECT * FROM users WHERE username = %s;", (user_input,))
쿼리μ λ°μ΄ν°λ₯Ό μ λ¬ν λλ νμ μ΄ λ°©λ²μ μ¬μ©νμΈμ. `(user_input,)`μ νν μΌνλ λ¨μΌ μμμΌμ§λΌλ Pythonμ΄ ννμ μμ±νλλ‘ λ³΄μ₯νλ λ° μ€μν©λλ€.
CREATE: λ°μ΄ν° μ½μ
λ°μ΄ν°λ₯Ό μ½μ νλ €λ©΄ `INSERT` λ¬Έμ μ¬μ©ν©λλ€. 쿼리 μ€ν ν λ³κ²½ μ¬νμ μꡬμ μΌλ‘ λ§λ€λ €λ©΄ νΈλμμ μ 컀λ°ν΄μΌ ν©λλ€.
# Assume we have a table: CREATE TABLE employees (id SERIAL PRIMARY KEY, name VARCHAR(100), department VARCHAR(50));
try:
with psycopg2.connect(...) as conn:
with conn.cursor() as cur:
sql = "INSERT INTO employees (name, department) VALUES (%s, %s);"
cur.execute(sql, ("Alice Wonderland", "Engineering"))
# Commit the transaction to make the changes permanent
conn.commit()
print("Employee record inserted successfully.")
except (Exception, psycopg2.DatabaseError) as error:
print(error)
# If an error occurs, you might want to rollback any partial changes
# conn.rollback() # The 'with' statement handles this implicitly on error exit
μ¬λ¬ ν μ½μ
μ¬λ¬ νμ μ½μ ν λ `execute()`μ ν¨κ» 루νλ₯Ό μ¬μ©νλ κ²μ λΉν¨μ¨μ μ λλ€. Psycopg2λ ν¨μ¬ λΉ λ₯Έ `executemany()` λ©μλλ₯Ό μ 곡ν©λλ€.
# ... inside the cursor block
employees_to_add = [
("Bob Builder", "Construction"),
("Charlie Chaplin", "Entertainment"),
("Dora Explorer", "Logistics")
]
sql = "INSERT INTO employees (name, department) VALUES (%s, %s);"
cur.executemany(sql, employees_to_add)
conn.commit()
print(f"{cur.rowcount} records inserted successfully.")
READ: λ°μ΄ν° κ°μ Έμ€κΈ°
λ°μ΄ν° μ½κΈ°λ `SELECT` λ¬ΈμΌλ‘ μνλ©λλ€. 쿼리λ₯Ό μ€νν ν 컀μμ fetch λ©μλ μ€ νλλ₯Ό μ¬μ©νμ¬ κ²°κ³Όλ₯Ό κ²μν©λλ€.
fetchone(): 쿼리 κ²°κ³Ό μΈνΈμ λ€μ νμ κ²μνκ³ λ¨μΌ ννμ λ°ννλ©°, λ μ΄μ λ°μ΄ν°κ° μμΌλ©΄ `None`μ λ°νν©λλ€.fetchall(): 쿼리 κ²°κ³Όμ λλ¨Έμ§ λͺ¨λ νμ κ°μ Έμ νν λͺ©λ‘μ λ°νν©λλ€. λ§€μ° ν° κ²°κ³Ό μΈνΈμλ λ§μ λ©λͺ¨λ¦¬λ₯Ό μλΉν μ μμΌλ―λ‘ μ£Όμν΄μ μ¬μ©νμΈμ.fetchmany(size=cursor.arraysize): 쿼리 κ²°κ³Όμμ λ€μ ν μΈνΈλ₯Ό κ°μ Έμ νν λͺ©λ‘μ λ°νν©λλ€. λ μ΄μ νμ΄ μμΌλ©΄ λΉ λͺ©λ‘μ΄ λ°νλ©λλ€.
# ... inside the cursor block
cur.execute("SELECT name, department FROM employees WHERE department = %s;", ("Engineering",))
print("Fetching all engineering employees:")
all_engineers = cur.fetchall()
for engineer in all_engineers:
print(f"Name: {engineer[0]}, Department: {engineer[1]}")
# Example with fetchone to get a single record
cur.execute("SELECT name FROM employees WHERE id = %s;", (1,))
first_employee = cur.fetchone()
if first_employee:
print(f"Employee with ID 1 is: {first_employee[0]}")
UPDATE: λ°μ΄ν° μμ
κΈ°μ‘΄ λ μ½λλ₯Ό μ λ°μ΄νΈνλ €λ©΄ `UPDATE` λ¬Έμ μ¬μ©ν©λλ€. μμ ν νμ μ§μ νκΈ° μν΄ `WHERE` μ μ μ¬μ©νκ³ , νμ λ§€κ°λ³μ λ체λ₯Ό μ¬μ©νλ κ²μ κΈ°μ΅νμΈμ.
# ... inside the cursor block
sql = "UPDATE employees SET department = %s WHERE name = %s;"
cur.execute(sql, ("Senior Management", "Alice Wonderland"))
conn.commit()
print(f"{cur.rowcount} record(s) updated.")
DELETE: λ°μ΄ν° μ κ±°
λ§μ°¬κ°μ§λ‘ `DELETE` λ¬Έμ λ μ½λλ₯Ό μ κ±°ν©λλ€. ν μ΄λΈ μ 체λ₯Ό μ€μλ‘ μμ νλ κ²μ νΌνλ €λ©΄ `WHERE` μ μ΄ μ¬κΈ°μμ μ€μν©λλ€.
# ... inside the cursor block
sql = "DELETE FROM employees WHERE name = %s;"
cur.execute(sql, ("Charlie Chaplin",))
conn.commit()
print(f"{cur.rowcount} record(s) deleted.")
νΈλμμ κ΄λ¦¬: λ°μ΄ν° λ¬΄κ²°μ± λ³΄μ₯
νΈλμμ μ κ΄κ³ν λ°μ΄ν°λ² μ΄μ€μ ν΅μ¬ κ°λ μ λλ€. νΈλμμ μ λ¨μΌ λ Όλ¦¬μ μμ λ¨μλ‘ μνλλ μΌλ ¨μ μμ μ λλ€. νΈλμμ μ μ£Όμ μμ±μ μ’ μ’ ACIDλΌλ μ½μ΄λ‘ μμ½λ©λλ€: Atomicity(μμμ±), Consistency(μΌκ΄μ±), Isolation(격리μ±), Durability(μμμ±).
psycopg2μμ νΈλμμ μ 첫 λ²μ§Έ SQL λͺ λ Ήμ μ€νν λ μλμΌλ‘ μμλ©λλ€. νΈλμμ μ μ’ λ£νλ λ°©λ²μ λ€μ μ€ νλμ λλ€:
- 컀λ°: `conn.commit()`μ νΈλμμ λ΄μμ λ³κ²½λ λͺ¨λ λ΄μ©μ λ°μ΄ν°λ² μ΄μ€μ μ μ₯ν©λλ€.
- λ‘€λ°±: `conn.rollback()`μ νΈλμμ λ΄μμ λ³κ²½λ λͺ¨λ λ΄μ©μ μ·¨μν©λλ€.
μ μ ν νΈλμμ κ΄λ¦¬λ λ§€μ° μ€μν©λλ€. λ μν κ³μ’ κ°μ μκΈμ μ΄μ²΄νλ μν©μ μμν΄ λ³΄μΈμ. ν κ³μ’μμ μΈμΆνκ³ λ€λ₯Έ κ³μ’λ‘ μ κΈν΄μΌ ν©λλ€. λ μμ λͺ¨λ μ±κ³΅ν΄μΌ νκ±°λ, λ λ€ μ±κ³΅νμ§ μμμΌ ν©λλ€. μΈμΆμ΄ μ±κ³΅ν ν μ κΈ μμ μ΄ μ€ν¨νλ©΄ λ°μ΄ν° λΆμΌμΉλ₯Ό λ°©μ§νκΈ° μν΄ μΈμΆμ λ‘€λ°±ν΄μΌ ν©λλ€.
# A robust transaction example
conn = None
try:
conn = psycopg2.connect(...)
with conn.cursor() as cur:
# Operation 1: Debit from account A
cur.execute("UPDATE accounts SET balance = balance - 100 WHERE id = 1;")
# Operation 2: Credit to account B
cur.execute("UPDATE accounts SET balance = balance + 100 WHERE id = 2;")
# If both operations succeed, commit the transaction
conn.commit()
print("Transaction completed successfully.")
except (Exception, psycopg2.DatabaseError) as error:
print(f"Error in transaction: {error}")
# If there is any error, roll back the changes
if conn:
conn.rollback()
print("Transaction rolled back.")
finally:
# Ensure the connection is closed
if conn:
conn.close()
`with psycopg2.connect(...) as conn:` ν¨ν΄μ μ΄λ₯Ό λ¨μνν©λλ€. λΈλ‘μ΄ μ μμ μΌλ‘ μ’ λ£λλ©΄ psycopg2λ μμμ μΌλ‘ 컀λ°ν©λλ€. μμΈλ‘ μΈν΄ μ’ λ£λλ©΄ μμμ μΌλ‘ λ‘€λ°±ν©λλ€. μ΄λ λ§μ μ¬μ© μ¬λ‘μμ μ’ μ’ μΆ©λΆνκ³ ν¨μ¬ κΉλν©λλ€.
Psycopg2μ κ³ κΈ κΈ°λ₯
μ¬μ μ¬μ©νκΈ° (DictCursor)
κΈ°λ³Έμ μΌλ‘ fetch λ©μλλ ννμ λ°νν©λλ€. μΈλ±μ€λ‘ λ°μ΄ν°μ μ κ·Όνλ κ²(μ: `row[0]`, `row[1]`)μ μ½κ³ μ μ§λ³΄μνκΈ° μ΄λ €μΈ μ μμ΅λλ€. Psycopg2λ `DictCursor`μ κ°μ νΉμ 컀μλ₯Ό μ 곡νλ©°, μ΄λ νμ μ¬μ κ³Ό μ μ¬ν κ°μ²΄λ‘ λ°ννμ¬ μ΄λ¦μΌλ‘ μ΄μ μ κ·Όν μ μλλ‘ ν©λλ€.
from psycopg2.extras import DictCursor
# ... inside the 'with psycopg2.connect(...) as conn:' block
# Note the cursor_factory argument
with conn.cursor(cursor_factory=DictCursor) as cur:
cur.execute("SELECT id, name, department FROM employees WHERE id = %s;", (1,))
employee = cur.fetchone()
if employee:
print(f"ID: {employee['id']}, Name: {employee['name']}")
PostgreSQL λ°μ΄ν° μ ν μ²λ¦¬
Psycopg2λ Python μ νκ³Ό PostgreSQL μ ν κ°μ μλ λ³νμ νλ₯νκ² μνν©λλ€.
- Python `None`μ SQL `NULL`μ λ§€νλ©λλ€.
- Python `int`λ `integer`μ λ§€νλ©λλ€.
- Python `float`λ `double precision`μ λ§€νλ©λλ€.
- Python `datetime` κ°μ²΄λ `timestamp`μ λ§€νλ©λλ€.
- Python `list`λ PostgreSQL `ARRAY` μ νμ λ§€νλ μ μμ΅λλ€.
- Python `dict`λ `JSONB` λλ `JSON`μ λ§€νλ μ μμ΅λλ€.
μ΄λ¬ν μνν μ μμ 볡μ‘ν λ°μ΄ν° κ΅¬μ‘°λ‘ μμ νλ κ²μ λλλλ‘ μ§κ΄μ μΌλ‘ λ§λλλ€.
μ μΈκ³ κ°λ°μλ₯Ό μν μ±λ₯ λ° λͺ¨λ² μ¬λ‘
κΈ°λ₯μ μΈ λ°μ΄ν°λ² μ΄μ€ μ½λλ₯Ό μμ±νλ κ²κ³Ό μ±λ₯μ΄ λ°μ΄λκ³ κ²¬κ³ ν μ½λλ₯Ό μμ±νλ κ²μ λ€λ¦ λλ€. λ€μμ κ³ νμ§ μ ν리μΌμ΄μ μ ꡬμΆνκΈ° μν νμμ μΈ κ΄νμ λλ€.
μ°κ²° νλ§
μ λ°μ΄ν°λ² μ΄μ€ μ°κ²°μ μ€μ νλ κ²μ λΉμ©μ΄ λ§μ΄ λλ μμ μ λλ€. μ¬κΈ°μλ λ°μ΄ν°λ² μ΄μ€ μλ²μμ λ€νΈμν¬ νΈλμ °μ΄ν¬, μΈμ¦ λ° νλ‘μΈμ€ μμ±μ΄ ν¬ν¨λ©λλ€. μΉ μ ν리μΌμ΄μ λλ λ§μ λμ μμ²μ μ²λ¦¬νλ λͺ¨λ μλΉμ€μμ κ° μμ²λ§λ€ μ μ°κ²°μ μμ±νλ κ²μ λ§€μ° λΉν¨μ¨μ μ΄λ©° νμ₯λμ§ μμ΅λλ€.
ν΄κ²°μ± μ μ°κ²° νλ§μ λλ€. μ°κ²° νμ λ°μ΄ν°λ² μ΄μ€ μ°κ²°μ μΊμμ΄λ©°, μ¬μ¬μ©λ μ μλλ‘ μ μ§ κ΄λ¦¬λ©λλ€. μ ν리μΌμ΄μ μ΄ μ°κ²°μ νμλ‘ ν λ νμμ νλλ₯Ό λΉλ¦½λλ€. μμ μ΄ λλλ©΄ μ°κ²°μ λ«λ λμ νμ λ°νν©λλ€.
Psycopg2λ `psycopg2.pool` λͺ¨λμ λ΄μ₯λ μ°κ²° νμ μ 곡ν©λλ€.
import psycopg2.pool
import os
# Create the connection pool once when your application starts.
# The minconn and maxconn parameters control the pool size.
connection_pool = psycopg2.pool.SimpleConnectionPool(
minconn=1,
maxconn=10,
dbname=os.environ.get("DB_NAME"),
user=os.environ.get("DB_USER"),
password=os.environ.get("DB_PASSWORD"),
host=os.environ.get("DB_HOST", "127.0.0.1")
)
def execute_query_from_pool(sql, params=None):
"""Function to get a connection from the pool and execute a query."""
conn = None
try:
# Get a connection from the pool
conn = connection_pool.getconn()
with conn.cursor() as cur:
cur.execute(sql, params)
# In a real app, you might fetch and return results here
conn.commit()
print("Query executed successfully.")
except (Exception, psycopg2.DatabaseError) as error:
print(f"Error executing query: {error}")
finally:
if conn:
# Return the connection to the pool
connection_pool.putconn(conn)
# When your application shuts down, close all connections in the pool
# connection_pool.closeall()
μ€λ₯ μ²λ¦¬
μ€λ₯ μ²λ¦¬λ₯Ό ꡬ체μ μΌλ‘ νμΈμ. Psycopg2λ `psycopg2.Error`λ₯Ό μμνλ λ€μν μμΈλ₯Ό λ°μμν΅λλ€. `IntegrityError`(κΈ°λ³Έ ν€ μλ°) λλ `OperationalError`(μ°κ²° λ¬Έμ )μ κ°μ νΉμ μλΈν΄λμ€λ₯Ό ν¬μ°©νλ©΄ λ€μν μ€ν¨ μλ리μ€λ₯Ό λ μ°μνκ² μ²λ¦¬ν μ μμ΅λλ€.
λ―Έλ: Psycopg 3
μ€λλ psycopg2κ° μμ μ μ΄κ³ μ§λ°°μ μΈ μ΄λν°μ΄μ§λ§, κ·Έ νμμμΈ Psycopg 3κ° μΆμλμ΄ λ―Έλλ₯Ό λννλ€λ μ μ μ£Όλͺ©ν κ°μΉκ° μμ΅λλ€. μ΄λ λ λμ μ±λ₯, ν₯μλ κΈ°λ₯, κ·Έλ¦¬κ³ κ°μ₯ μ€μν Pythonμ `asyncio` νλ μμν¬μ λν λ€μ΄ν°λΈ μ§μμ μ 곡νκΈ° μν΄ μ²μλΆν° λ€μ μμ±λμμ΅λλ€. μ΅μ λΉλκΈ° Pythonμ μ¬μ©νλ μ νλ‘μ νΈλ₯Ό μμνλ κ²½μ° Psycopg 3λ₯Ό νμνλ κ²μ΄ κ°λ ₯ν κΆμ₯λ©λλ€.
κ²°λ‘
Python, PostgreSQL, κ·Έλ¦¬κ³ psycopg2μ μ‘°ν©μ λ°μ΄ν° μ€μ¬ μ ν리μΌμ΄μ μ ꡬμΆνκΈ° μν κ°λ ₯νκ³ μ λ’°ν μ μμΌλ©° κ°λ°μ μΉνμ μΈ μ€νμ μ 곡ν©λλ€. μ°λ¦¬λ μμ ν μ°κ²° μ€μ λΆν° CRUD μμ μ€ν, νΈλμμ κ΄λ¦¬, κ·Έλ¦¬κ³ μ°κ²° νλ§κ³Ό κ°μ μ±λ₯μ μ€μν κΈ°λ₯ ꡬνκΉμ§ μ΄ν΄λ³΄μμ΅λλ€.
μ΄λ¬ν κ°λ μ μλ¬νκ³ λͺ¨λ² μ¬λ‘, νΉν λ§€κ°λ³μνλ 쿼리λ₯Ό ν΅ν 보μκ³Ό μ°κ²° νμ ν΅ν νμ₯μ±μ κΎΈμ€ν μ μ©ν¨μΌλ‘μ¨ μ μΈκ³ μ¬μ©μ κΈ°λ°μ μλΉμ€λ₯Ό μ 곡ν μ μλ κ²¬κ³ ν μ ν리μΌμ΄μ μ ꡬμΆν μ€λΉλ₯Ό κ°μΆκ² λ©λλ€. ν΅μ¬μ κΈ°λ₯μ μΌ λΏλ§ μλλΌ μ₯κΈ°μ μΌλ‘ μμ νκ³ ν¨μ¨μ μ΄λ©° μ μ§λ³΄μ κ°λ₯ν μ½λλ₯Ό μμ±νλ κ²μ λλ€. μ¦κ±°μ΄ μ½λ© λμΈμ!